package com.demo.aop.aspect;

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

//两个缺一不可
@Component
@Aspect
@Order(2) // 定义切面优先级 数字越小 级别越高
public class LoggingAspectjProxy {

	/**
	 * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码. 使用 @Pointcut 来声明切入点表达式.
	 * 后面的其他通知直接使用方法名来引用当前的切入点表达式.
	 */
	// @Pointcut("execution(int com.project.calculator.Calculator.*(..))")
	@Pointcut("execution(public int com.demo.aop.service.Calculator.*(..))")
	public void declareJoinPointExpresson() {
	}

	/**
	 * "*"相当于通配符 前置通知
	 * 
	 * @param joinpoint
	 */
	// @Before("execution(int com.project.calculator.CalculatorImp.*(..))")
	@Before("declareJoinPointExpresson()")
	public void beforeMethod(JoinPoint joinpoint) {
		String methodname = joinpoint.getSignature().getName();

		Object[] ars = joinpoint.getArgs();

		System.out.println("before Method: " + methodname + " args:" + Arrays.asList(ars) + "start");
	}

	/**
	 * 后置通知 有异常以照常执行
	 * 
	 * @param joinpoint
	 */
	// @After("execution(int com.project.calculator.CalculatorImp.*(..))")
	@After("declareJoinPointExpresson()")
	public void afterMethod(JoinPoint joinpoint) {

		String methodname = joinpoint.getSignature().getName();

		System.out.println("after Method: " + methodname + " ends");
	}

	/**
	 * 返回通知 可以访问返回值 前面两个方法都不可以访问
	 * 
	 * @param joinpoint
	 */

	// @AfterReturning(value = "execution(int
	// com.project.calculator.CalculatorImp.*(..))", returning = "result")
	@AfterReturning(value = "declareJoinPointExpresson()", returning = "result")
	public void returnMethod(JoinPoint joinpoint, Object result) {

		String methodname = joinpoint.getSignature().getName();

		System.out.println("return Method:" + methodname + " result=" + result);
	}

	/**
	 * 异常通知 有异常才会触发
	 * 
	 * @param joinpoint
	 * @param ex
	 *            可以定义异常 精准抛出 比如NullPointerException 遇到空指针异常才会throw
	 */
	// @AfterThrowing(value = "execution(int
	// com.project.calculator.CalculatorImp.*(..))", throwing = "ex")
	@AfterThrowing(value = "declareJoinPointExpresson()", throwing = "ex")
	public void throwingMethod(JoinPoint joinpoint, Exception ex) {

		String methodname = joinpoint.getSignature().getName();

		System.out.println("Throwing Method:" + methodname + " throwing=" + ex);
	}

	/**
	 * 环绕通知需要携带 ProceedingJoinPoint 类型的参数. 环绕通知类似于动态代理的全过程: ProceedingJoinPoint
	 * 类型的参数可以决定是否执行目标方法. 且环绕通知必须有返回值, 返回值即为目标方法的返回值 ***********最强大 但不代表最常用
	 */
	// @Around("declareJoinPointExpresson()")
	// public Object aroundMethod(ProceedingJoinPoint pjd) {
	//
	// Object result = null;
	// String methodName = pjd.getSignature().getName();
	//
	// try {
	// // 前置通知
	// System.out.println("The method " + methodName + " begins with " +
	// Arrays.asList(pjd.getArgs()));
	// // 执行目标方法
	// result = pjd.proceed();
	// // 返回通知
	// System.out.println("The method " + methodName + " ends with " + result);
	// } catch (Throwable e) {
	// // 异常通知
	// System.out.println("The method " + methodName + " occurs exception:" +
	// e);
	// throw new RuntimeException(e);//解决null转换异常
	// }
	// // 后置通知
	// System.out.println("The method " + methodName + " ends");
	//
	// return result;
	// }
}